﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using System.Web.Configuration;
using System.Xml;
using System.Xml.Serialization;
using System.Diagnostics;
using System.Data;
using Microsoft.VisualBasic;
using System.Runtime.CompilerServices;
using FSY.API.CacheManager;
using FSY.Globals;
namespace FSY.API.Utilities
{
    public class Fsy_CBOUtil
    {
        #region private constants
        private const int defaultCacheTimeOut = 20;
        private const string objMapCacheKey = "objMap_";
        #endregion

        #region Lấy ObjectMapingInfo
        private static ObjectMapingInfo GetObjectMapping(Type objType)
        {
            string cacheKey = objMapCacheKey + objType.FullName;
            ObjectMapingInfo objMap = Fsy_Cache.GetCache(cacheKey) as ObjectMapingInfo;
            if (objMap == null)
            {
                objMap = new ObjectMapingInfo();
                objMap.ObjectType = objType.FullName;
                objMap.PrimaryKey = GetPrimaryKey(objType);
                objMap.TableName = GetTableName(objType);

                foreach (PropertyInfo objPropertyInfo in objType.GetProperties())
                {
                    objMap.Properties.Add(objPropertyInfo.Name.ToUpperInvariant(), objPropertyInfo);
                    objMap.ColumnName.Add(objPropertyInfo.Name.ToUpperInvariant(), GetColumnName(objPropertyInfo));
                }
                Fsy_Cache.SetCache(cacheKey, objMap);
            }
            return objMap;
        }
        private static string GetColumnName(PropertyInfo objPropertyInfo)
        {
            string columnName = objPropertyInfo.Name;
            return columnName;
        }
        private static string GetTableName(Type objType)
        {
            string tableName = objType.Name;
            if (tableName.EndsWith("Info"))
                tableName.Replace("Info", string.Empty);
            return tableName;
        }
        private static string GetPrimaryKey(Type objType)
        {
            return "ItemID";
        }
        #endregion

        public static object CreateObjectFromReader(Type objType, IDataReader dr, bool closeDataReader)
        {
            object objObject = new object();
            bool isSuccess = Fsy_Null.NullBoolean;
            bool canRead = true;
            if (closeDataReader)
            {
                canRead = false;
                if (dr.Read())
                    canRead = true;
            }
            try
            {
                if (canRead)
                {
                    objObject = CreateObject(objType, false);
                    FillObjectFromReader(objObject, dr);
                }
            }
            finally
            {
            }
            return objObject;

        }
        public static void InitializeObject(object obj)
        {
            ObjectMapingInfo objMap = GetObjectMapping(obj.GetType());
            foreach (PropertyInfo objPropertiyInfo in objMap.Properties.Values)
            {
                if (objPropertiyInfo.CanWrite)
                    objPropertiyInfo.SetValue(obj, Fsy_Null.SetNull(objPropertiyInfo), null);
            }
        }
        public static object CreateObject(Type objType, bool initialize)
        {
            object obj = Activator.CreateInstance(objType);
            if (initialize)
                InitializeObject(obj);
            return obj;
        }
        private static void FillObjectFromReader(object objObject, IDataReader dr)
        {
            try
            {
                Type objPropertyType = null;
                PropertyInfo objPropertyInfo = null;
                object objDataValue;
                Type objDataType;
                ObjectMapingInfo objMap = GetObjectMapping(objObject.GetType());
                int index;
                for (index = 0; index < dr.FieldCount; index++)
                {
                    if (objMap.Properties.TryGetValue(dr.GetName(index).ToUpperInvariant(), out objPropertyInfo))
                    {
                        objPropertyType = objPropertyInfo.PropertyType;
                        if (objPropertyInfo.CanWrite)
                        {
                            objDataValue = dr.GetValue(index);
                            objDataType = objDataValue.GetType();
                            if (Information.IsDBNull(objDataValue))
                            {
                                objPropertyInfo.SetValue(objObject, Fsy_Null.SetNull(objPropertyInfo), null);
                            }
                            else if (objPropertyType.Equals(objDataType))
                            {
                                objPropertyInfo.SetValue(objObject, objDataValue, null);
                            }
                            else
                            {
                                try
                                {
                                    if (objPropertyType.BaseType.Equals(Type.GetType("System.Enum")))
                                    {
                                        if (Information.IsNumeric(objDataValue))
                                        {
                                            objPropertyInfo.SetValue(objObject, Enum.ToObject(objPropertyType, Convert.ToInt32(objDataValue)), null);
                                        }
                                        else
                                        {
                                            objPropertyInfo.SetValue(objObject, Enum.ToObject(objPropertyType, objDataValue), null);
                                        }
                                    }
                                    else if (objPropertyType.FullName.Equals("System.Guid"))
                                    {
                                        objPropertyInfo.SetValue(objObject, Convert.ChangeType(new Guid(objDataValue.ToString()), objPropertyType), null);
                                    }
                                    else if (objPropertyType.FullName.Equals("System.Version"))
                                    {
                                        objPropertyInfo.SetValue(objObject, new Version(objDataValue.ToString()), null);
                                    }
                                    else
                                    {
                                        objPropertyInfo.SetValue(objObject, objDataValue, null);
                                    }
                                }
                                catch
                                {
                                    objPropertyInfo.SetValue(objObject, Convert.ChangeType(objDataValue, objPropertyType), null);
                                }
                            }
                        }
                    }
                }
            }
            catch
            {
            }
        }
        public static Dictionary<string, PropertyInfo> GetProperties(Type objType)
        {
            return GetObjectMapping(objType).Properties;
        }
        public static void CloseDataReader(IDataReader dr, bool closeDataReader)
        {
            if (dr != null && closeDataReader)
            {
                dr.Close();
            }
        }
        private static IList<T> FillListFromReader<T>(IDataReader dr, IList<T> objList, bool closeReader)
        {
            T objObject;
            bool isSucces = Fsy_Null.NullBoolean;
            try
            {
                if (dr.IsClosed) return null;
                while (dr.Read())
                {
                    objObject = (T)CreateObjectFromReader(typeof(T), dr, false);
                    objList.Add(objObject);
                }
                isSucces = true;
            }
            catch(InvalidOperationException ex)
            {
                FsyLoggerHelper.WriteError("FSY.API.Utilities.Fsy_CBOUtil - FillListFromReader<T>(IDataReader dr, IList<T> objList, bool closeReader) " + ex.Message);
            }
            finally
            {
                if (isSucces == false)
                    closeReader = true;
                CloseDataReader(dr, closeReader);
            }
            return objList;
        }        
        private static IList FillListFromReader(Type objType, IDataReader dr, IList objList, bool closeDataReader)
        {
            object objObject;
            bool isSuccess = Fsy_Null.NullBoolean;
            try
            {
                while (dr.Read())
                {
                    objObject = CreateObjectFromReader(objType, dr, false);
                    objList.Add(objObject);
                }
                isSuccess = true;
            }
            finally
            {
                if (!isSuccess)
                    closeDataReader = true;
                CloseDataReader(dr, closeDataReader);
            }
            return objList;
        }
        public static List<T> FillCollection<T>(IDataReader dr)
        {
            return (List<T>)FillListFromReader<T>(dr, new List<T>(), true);
        }
        public static IList FillCollection(IDataReader dr, Type objType, IList objToFill)
        {
            return FillListFromReader(objType, dr, objToFill, true);
        }       
        public static ArrayList FillCollection(IDataReader dr, Type objType)
        {
            ArrayList lst = new ArrayList();
            return (ArrayList)FillListFromReader(objType, dr, lst, true);
        }
        public static ArrayList FillCollection(Type objType, IDataReader dr, int totalRecord)
        {
            ArrayList objList = (ArrayList)FillListFromReader(objType, dr, new ArrayList(), false);
            try
            {
                if (dr.NextResult())
                    totalRecord = Common.GetTotalRecords(dr);
            }
            catch
            {
                //Lưu file log thong qua Exceptions.cs(Lop Exceptions.cs tu xây dựng)
            }
            finally
            {
                CloseDataReader(dr, true);
            }
            return objList;
        }       

        public static Object FillObject(Type objType, IDataReader dr)
        {
            return CreateObjectFromReader(objType, dr, true);
        }
        private static Object FillObject(Type objType, IDataReader dr, bool closeDataReader)
        {
            return CreateObjectFromReader(objType, dr, closeDataReader);
        }

        public static XmlDocument Serialize(object objObject)
        {
            XmlSerializer serializer = new XmlSerializer(objObject.GetType());
            StringBuilder sb = new StringBuilder();
            TextWriter textWriter = new StringWriter(sb);
            serializer.Serialize(textWriter, RuntimeHelpers.GetObjectValue(objObject));
            StringReader reader = new StringReader(textWriter.ToString());
            DataSet set = new DataSet();
            set.ReadXml(reader);
            XmlDocument document2 = new XmlDocument();
            document2.LoadXml(set.GetXml());
            return document2;
        }
    }
}
